import webpack from "webpack";
import { readdirSync, statSync } from "fs-extra";
import { join } from "path";
import TerserPlugin from "terser-webpack-plugin";
import { AutoJSUI } from "./autojsUi";
import { Configuration } from "webpack";
import { AutoJSNode } from "./autojsNode";
import { AutoJsRhino } from './autoJsRhino';
import { AutoJsNodeUi } from "./autoJsNodeUi";
import { AutoJsFloat } from "./autoJsFloat";

export function getSourceFile(root: string): string[] {
    const srcFiles = readdirSync(root);
    return srcFiles.map(file => {
        const stat = statSync(join(root, file))
        if (stat.isDirectory()) {
            // return getSourceFile(join(root, file)).flat()
            return []
        } else {
            return [
                join(root, file)
            ]
        }
    }).flat()
}
export function getEntry(root: string) {
    const scriptRoot = root;
    const srcFiles = getSourceFile(scriptRoot);
    const entries: { [name: string]: string } = {};
    srcFiles.map((item, index) => {
        const [name, type, ...exts] = item.split('.')
        if (name && type && exts.length > 0) {
            const scriptName = name.replace(root, '')
            exts.pop();
            if (exts.length > 0) {
                entries[`${scriptName}.${type}.${exts.join('.')}`] = srcFiles[index]
            } else {
                entries[`${scriptName}.${type}`] = srcFiles[index]
            }
        }
    });
    return entries;
}
function checkUIScript(entries: { [name: string]: string }) {
    const arr = Object.entries(entries).map(([name, value]) => {
        const [, type, ...exts] = name.split('.')
        if (type === 'ui' && exts.length === 0) {
            return name
        };
        return null
    });
    return <string[]>arr.filter(val => !!val);
}
function checkNodeScript(entries: { [name: string]: string }) {
    const arr = Object.entries(entries).map(([name, value]) => {
        const [, type, ...exts] = name.split('.')
        if (type === 'node' && exts.length === 0) {
            return name
        };
        return null
    });
    return <string[]>arr.filter(val => !!val);
}
function checkNodeUiScript(entries: { [name: string]: string }) {
    const arr = Object.entries(entries).map(([name, value]) => {
        const [, type, ...exts] = name.split('.')
        console.log({ type, exts })
        if (type === 'ui' && exts.length > 0) {
            return name
        };
        return null
    });
    return <string[]>arr.filter(val => !!val);
}


function checkRhinoScript(entries: { [name: string]: string }) {
    const arr = Object.entries(entries).map(([name, value]) => {
        const [, type, ...exts] = name.split('.')
        if (type === 'rhino' && exts.length === 0) {
            return name
        };
        return null
    });
    return <string[]>arr.filter(val => !!val);
}
function checkFloatScript(entries: { [name: string]: string }) {
    const arr = Object.entries(entries).map(([name, value]) => {
        const [, type, ...exts] = name.split('.')
        if (type === 'float' && exts.length === 0) {
            return name
        };
        return null
    });
    return <string[]>arr.filter(val => !!val);
}
export function build(projectRoot: string, watch: boolean = false, cb?: Function) {
    const entryList = getEntry(projectRoot)
    const uiEntry = checkUIScript(entryList)
    const nodeEntry = checkNodeScript(entryList)
    const nodeUiEntry = checkNodeUiScript(entryList)
    const rhinoEntry = checkRhinoScript(entryList)
    const floatEntry = checkFloatScript(entryList)
    const plugins: webpack.WebpackPluginInstance[] = [
        new AutoJSUI(uiEntry),
        new AutoJSNode(nodeEntry),
        new AutoJsNodeUi(nodeUiEntry),
        new AutoJsRhino(rhinoEntry),
        new AutoJsFloat(floatEntry),
    ];
    const options: Configuration = {
        entry: entryList,
        output: {
            path: join(projectRoot, '../'),
            filename: '[name].js'
        },
        externals: {
            ui_object: `commonjs ui_object`,
            ui: `commonjs ui`,
            toast: `commonjs toast`,
            java_utils: `commonjs java_utils`,
            lang: `commonjs lang`,
            lazy_ui_object: `commonjs lazy_ui_object`,
            rhino: `commonjs rhino`,
            engines: `commonjs engines`,
            color: `commonjs color`,
            image: `commonjs image`,
            shell: `commonjs shell`,
            app: `commonjs app`,
            'ui/view': `commonjs ui/view`,
            'ui/web': `commonjs ui/web`,
            'ui/layout': `commonjs ui/layout`,
            'ui/util': `commonjs ui/util`,
            "ui/activity": `commonjs ui/activity`,
            device: `commonjs device`,
            ui_selector: `commonjs ui_selector`,
            settings: `commonjs settings`,
            accessibility: `commonjs accessibility`,
            clip_manager: `commonjs clip_manager`,
            datastore: `commonjs datastore`,
            dialogs: `commonjs dialogs`,
            floating_window: `commonjs floating_window`,
            handler_thread: `commonjs handler_thread`,
            media: `commonjs media`,
            media_projection: `commonjs media_projection`,
            power_manager: `commonjs power_manager`,
            path: `commonjs path`,
            axios: `commonjs axios`,
            fs: `commonjs fs`,
            util: `commonjs util`,
            stream: `commonjs stream`,
            events: `commonjs events`,
            plugins: `commonjs plugins`,
            notification: `commonjs notification`,
            ws: `commonjs ws`,
            http: `commonjs http`,
            crypto: `commonjs crypto`,
            work_manager: `commonjs work_manager`,
            [`@autojs/opencv`]: `commonjs @autojs/opencv`,
            android: `commonjs android`,
            worker_threads: `commonjs worker_threads`
        },
        resolve: {
            extensions: ['.ts', '.tsx', '.js'],
            alias: {}
        },
        optimization: {
            sideEffects: true,
            minimize: false,
        },
        module: {
            rules: [
                {
                    test: /\.xml$/,
                    use: ['raw-loader']
                },
                {
                    test: /\.tsx?$/,
                    use: {
                        loader: 'ts-loader',
                        options: {
                            transpileOnly: true,
                            compilerOptions: {
                                target: 'es6',
                                module: 'es6',
                                lib: ['ES2015', 'ES2017', 'ES2016', 'ES2018'],
                                removeComments: true,
                                skipLibCheck: true,
                                jsx: "preserve",
                                jsxImportSource: "react"
                            }
                        }
                    },
                    exclude: /node_modules/
                },
                {
                    test: /\.(png|jpg)$/,
                    use: [
                        {
                            loader: 'url-loader'
                        }
                    ]
                }
            ]
        },
        plugins: plugins,
        target: "node"
    }
    options.optimization = options.optimization || {};
    options.optimization.minimize = true;
    options.optimization.minimizer = [
        new TerserPlugin({
            terserOptions: {
                compress: {
                    drop_console: false,
                    directives: false,
                    keep_classnames: true,
                    keep_fnames: true
                },
                mangle: {
                    keep_classnames: true,
                    keep_fnames: true
                }
            },
        })
    ]
    const complier = webpack(options)
    if (watch) {
        complier.watch({}, (err, stat) => {
            stat && log(err, stat);
            cb && cb()
        })
    } else {
        complier.run((err, stat) => {
            stat && log(err, stat)
            cb && cb()
        })
    }
}

function log(err: Error | null, stat: webpack.Stats) {
    if (err) {
        console.log(err);
    }
    if (stat?.hasErrors()) {
        stat.toJson().errors?.forEach((error) => {
            console.log(error);
        });
    }
    console.log(`\nCompiled on ${new Date().toLocaleString()}`);
    stat?.toJson().assets?.forEach((element: { name: string }) => {
        console.log(element.name);
    });
}